package com.example.palette.start;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class StartTaskSorter {
    public static StartTaskCenter sort(List<? extends IStartTask<?>> startList) {
        Map<Class<? extends IStartTask>, Integer> inMap = new HashMap<>();
        Deque<Class<? extends IStartTask>> deque = new ArrayDeque<>();
        Map<Class<? extends IStartTask>, IStartTask> resultMap = new HashMap<>();
        Map<Class<? extends IStartTask>, List<Class<? extends IStartTask>>> dependMap = new HashMap<>();
        for (IStartTask startTask : startList) {
            resultMap.put(startTask.getClass(), startTask);
            int dependenciesCount = startTask.getDependenciesCount();
            inMap.put(startTask.getClass(), dependenciesCount);
            if (dependenciesCount == 0) {
                deque.offer(startTask.getClass());
            } else {
                List<Class<? extends IStartTask<?>>> dependencies = startTask.dependencies();
                for (Class<? extends IStartTask<?>> depend : dependencies) {
                    List<Class<? extends IStartTask>> depends = dependMap.get(depend);
                    if (depends == null) {
                        depends = new ArrayList<>();
                        dependMap.put(depend, depends);
                    }
                    depends.add(startTask.getClass());
                }
            }
        }
        List<IStartTask<?>> result = new ArrayList<>();
        List<IStartTask<?>> mainList = new ArrayList<>();
        List<IStartTask<?>> threadList = new ArrayList<>();
        while (!deque.isEmpty()) {
            Class<? extends IStartTask> clazz = deque.poll();
            IStartTask<?> startTask = resultMap.get(clazz);
            if(startTask.inMainThread()){
                mainList.add(startTask);
            }else {
                threadList.add(startTask);
            }
            if (dependMap.containsKey(clazz)) {
                List<Class<? extends IStartTask>> depends = dependMap.get(clazz);
                for (Class<? extends IStartTask> child : depends) {
                    Integer number = inMap.get(child);
                    inMap.put(child, number - 1);
                    if (number - 1 == 0) {
                        deque.offer(child);
                    }
                }
            }
        }
        result.addAll(threadList);
        result.addAll(mainList);
        return new StartTaskCenter(result,resultMap,dependMap);
    }
}
